﻿using System;
using System.Reflection;

namespace Borg
{
    public class Composer
    {
        public void Close(SlotInfo slot)
        {
            Runtime.TaskQueue.Enqueue(
                TaskFactory.CreateCloseSlot(
                    slot,
                    TaskFactory.CreateTaskGroupId(),
                    Assembly.GetCallingAssembly()));
        }

        public void CloseSlots(ExtensionInfo extension)
        {
            Runtime.TaskQueue.Enqueue(
                TaskFactory.CreateCloseSlots(
                    extension,
                    TaskFactory.CreateTaskGroupId(),
                    Assembly.GetCallingAssembly()));
        }

        public ExtensionInfo CreateSharedExtension(ExtensionTypeInfo extensionTypeInfo)
        {
            return extensionTypeInfo.InternalCreateSharedExtension(
                null,
                AppDomain.CurrentDomain,
                true,
                TaskFactory.CreateTaskGroupId(),
                Assembly.GetCallingAssembly());
        }

        public ExtensionInfo CreateSharedExtension(ExtensionTypeInfo extensionTypeInfo, ExtensionInfo creator)
        {
            return extensionTypeInfo.InternalCreateSharedExtension(
                creator,
                AppDomain.CurrentDomain,
                true,
                TaskFactory.CreateTaskGroupId(),
                Assembly.GetCallingAssembly());
        }

        public ExtensionInfo CreateSharedExtension(ExtensionTypeInfo extensionTypeInfo, AppDomain appDomain)
        {
            return extensionTypeInfo.InternalCreateSharedExtension(
                null,
                appDomain,
                true,
                TaskFactory.CreateTaskGroupId(),
                Assembly.GetCallingAssembly());
        }

        public ExtensionInfo CreateSharedExtension(ExtensionTypeInfo extensionTypeInfo, ExtensionInfo creator, AppDomain appDomain)
        {
            return extensionTypeInfo.InternalCreateSharedExtension(
                creator,
                appDomain,
                true,
                TaskFactory.CreateTaskGroupId(),
                Assembly.GetCallingAssembly());
        }

        public ExtensionInfo CreateUniqueExtension(ExtensionTypeInfo extensionTypeInfo)
        {
            return Runtime.Invoke(
                extensionTypeInfo.createExtensionHandle,
                new object[]
                    {
                        true,
                        false,
                        AppDomain.CurrentDomain,
                        Assembly.GetCallingAssembly()
                    }) as ExtensionInfo;
        }

        public ExtensionInfo CreateUniqueExtension(ExtensionTypeInfo extensionTypeInfo, AppDomain appDomain)
        {
            return Runtime.Invoke(
                extensionTypeInfo.createExtensionHandle,
                new object[]
                    {
                        true,
                        false,
                        appDomain,
                        Assembly.GetCallingAssembly()
                    }) as ExtensionInfo;
        }

        public void Deregister(PluginInfo plugin)
        {
            Runtime.TaskQueue.Enqueue(
                TaskFactory.CreateDeregister(
                    plugin,
                    TaskFactory.CreateTaskGroupId(),
                    Assembly.GetCallingAssembly()));
        }

        public void Deregister(PlugTypeInfo plugTypeInfo)
        {
            Runtime.TaskQueue.Enqueue(
                TaskFactory.CreateDeregister(
                    plugTypeInfo,
                    TaskFactory.CreateTaskGroupId(),
                    Assembly.GetCallingAssembly()));
        }

        public void Deregister(SlotInfo slot)
        {
            Runtime.TaskQueue.Enqueue(
                TaskFactory.CreateDeregister(
                    slot,
                    TaskFactory.CreateTaskGroupId(),
                    Assembly.GetCallingAssembly()));
        }

        public void Deregister(PlugTypeInfo plugTypeInfo, SlotInfo si)
        {
            if (si == null)
                throw new ArgumentException();

            Runtime.TaskQueue.Enqueue(
                TaskFactory.CreateDeregister(
                    plugTypeInfo,
                    si,
                    TaskFactory.CreateTaskGroupId(),
                    Assembly.GetCallingAssembly()));
        }

        public void Deregister(SlotInfo slot, PlugTypeInfo pti)
        {
            if (pti == null)
                throw new ArgumentException();

            Runtime.TaskQueue.Enqueue(
                TaskFactory.CreateDeregister(
                    slot,
                    pti,
                    TaskFactory.CreateTaskGroupId(),
                    Assembly.GetCallingAssembly()));
        }

        public void DeregisterFromSlots(ExtensionInfo extension)
        {
            Runtime.TaskQueue.Enqueue(
                TaskFactory.CreateDeregisterFromSlots(
                    extension,
                    TaskFactory.CreateTaskGroupId(),
                    Assembly.GetCallingAssembly()));
        }

        public void DeregisterFromSlots(ExtensionInfo extension, ExtensionTypeInfo eti)
        {
            if (eti == null)
                throw new ArgumentException();

            Runtime.TaskQueue.Enqueue(
                TaskFactory.CreateDeregisterFromSlots(
                    extension,
                    eti,
                    TaskFactory.CreateTaskGroupId(),
                    Assembly.GetCallingAssembly()));
        }

        public void DeregisterPlugs(ExtensionTypeInfo extensionTypeInfo)
        {
            Runtime.TaskQueue.Enqueue(
                TaskFactory.CreateDeregisterPlugs(
                    extensionTypeInfo,
                    TaskFactory.CreateTaskGroupId(),
                    Assembly.GetCallingAssembly()));
        }

        public void DeregisterPlugs(ExtensionTypeInfo extensionTypeInfo, ExtensionInfo ei)
        {
            if (ei == null)
                throw new ArgumentException();

            Runtime.TaskQueue.Enqueue(
                TaskFactory.CreateDeregisterFromSlots(
                    ei,
                    extensionTypeInfo,
                    TaskFactory.CreateTaskGroupId(),
                    Assembly.GetCallingAssembly()));
        }

        public bool DeselectPlugs(SlotInfo slot, params PlugInfo[] plugs)
        {
            return (bool)Runtime.Invoke(
                new SlotInfo.SelectPlugHandler(
                    slot.InternalDeselectPlugs),
                new object[] { plugs });
        }

        public void EnableComposition()
        {
            Runtime.Instance.isCompositionAllowed = true;
        }

        public ExtensionInfo GetSharedExtension(ExtensionTypeInfo extensionTypeInfo)
        {
            return extensionTypeInfo.sharedExtension;
        }

        public ExtensionInfo GetSharedExtension(ExtensionTypeInfo extensionTypeInfo, bool createOnDemand)
        {
            return extensionTypeInfo.sharedExtension == null && createOnDemand
                       ? extensionTypeInfo.InternalCreateSharedExtension(
                           null,
                           AppDomain.CurrentDomain,
                           true,
                           TaskFactory.CreateTaskGroupId(),
                           Assembly.GetCallingAssembly())
                       : extensionTypeInfo.sharedExtension;
        }

        public ExtensionInfo GetSharedExtension(ExtensionTypeInfo extensionTypeInfo, bool createOnDemand, ExtensionInfo creator)
        {
            return extensionTypeInfo.sharedExtension == null && createOnDemand
                       ? extensionTypeInfo.InternalCreateSharedExtension(
                           creator,
                           AppDomain.CurrentDomain,
                           true,
                           TaskFactory.CreateTaskGroupId(),
                           Assembly.GetCallingAssembly())
                       : extensionTypeInfo.sharedExtension;
        }

        public void Open(SlotInfo slot)
        {
            Runtime.TaskQueue.Enqueue(
                TaskFactory.CreateOpenSlot(
                    slot,
                    true,
                    TaskFactory.CreateTaskGroupId(),
                    Assembly.GetCallingAssembly()));
        }

        public void OpenSlots(ExtensionInfo extension)
        {
            Runtime.TaskQueue.Enqueue(
                TaskFactory.CreateOpenSlots(
                    extension,
                    true,
                    TaskFactory.CreateTaskGroupId(),
                    Assembly.GetCallingAssembly()));
        }

        public void Plug(PlugInfo plug)
        {
            Runtime.TaskQueue.Enqueue(
                TaskFactory.CreatePlug(
                    plug,
                    true,
                    TaskFactory.CreateTaskGroupId(),
                    Assembly.GetCallingAssembly()));
        }

        public void Plug(SlotInfo slot)
        {
            Runtime.TaskQueue.Enqueue(
                TaskFactory.CreatePlug(
                    slot,
                    true,
                    TaskFactory.CreateTaskGroupId(),
                    Assembly.GetCallingAssembly()));
        }

        public void Plug(ExtensionTypeInfo extensionTypeInfo, ExtensionInfo ei)
        {
            if (ei == null)
                throw new ArgumentException();

            Runtime.TaskQueue.Enqueue(
                TaskFactory.CreatePlug(
                    extensionTypeInfo,
                    ei,
                    TaskFactory.CreateTaskGroupId(),
                    Assembly.GetCallingAssembly()));
        }

        public void Plug(PlugInfo plug, SlotInfo si)
        {
            if (si == null)
                throw new ArgumentException();

            Runtime.TaskQueue.Enqueue(
                TaskFactory.CreatePlug(
                    plug,
                    si,
                    true,
                    TaskFactory.CreateTaskGroupId(),
                    Assembly.GetCallingAssembly()));
        }

        public void Plug(PlugTypeInfo plugTypeInfo, SlotInfo si)
        {
            if (si == null)
                throw new ArgumentException();

            Runtime.TaskQueue.Enqueue(
                TaskFactory.CreatePlug(
                    plugTypeInfo,
                    si,
                    TaskFactory.CreateTaskGroupId(),
                    Assembly.GetCallingAssembly()));
        }

        public void Plug(SlotInfo slot, PlugInfo pi)
        {
            if (pi == null)
                throw new ArgumentException();

            Runtime.TaskQueue.Enqueue(
                TaskFactory.CreatePlug(
                    slot,
                    pi,
                    true,
                    TaskFactory.CreateTaskGroupId(),
                    Assembly.GetCallingAssembly()));
        }

        public void Plug(SlotInfo slot, PlugTypeInfo pti)
        {
            if (pti == null)
                throw new ArgumentException();

            Runtime.TaskQueue.Enqueue(
                TaskFactory.CreatePlug(
                    slot,
                    pti,
                    true,
                    TaskFactory.CreateTaskGroupId(),
                    Assembly.GetCallingAssembly()));
        }

        public void PlugInSlots(ExtensionInfo extension)
        {
            Runtime.TaskQueue.Enqueue(
                TaskFactory.CreatePlugInSlots(
                    extension,
                    true,
                    TaskFactory.CreateTaskGroupId(),
                    Assembly.GetCallingAssembly()));
        }

        public void PlugInSlots(ExtensionInfo extension, ExtensionInfo ei)
        {
            if (ei == null)
                throw new ArgumentException();

            Runtime.TaskQueue.Enqueue(
                TaskFactory.CreatePlugInSlots(
                    extension,
                    ei,
                    true,
                    TaskFactory.CreateTaskGroupId(),
                    Assembly.GetCallingAssembly()));
        }

        public void PlugInSlots(ExtensionInfo extension, ExtensionTypeInfo eti)
        {
            if (eti == null)
                throw new ArgumentException();

            Runtime.TaskQueue.Enqueue(
                TaskFactory.CreatePlugInSlots(
                    extension,
                    eti,
                    true,
                    TaskFactory.CreateTaskGroupId(),
                    Assembly.GetCallingAssembly()));
        }

        public void PlugPlugs(ExtensionInfo extension)
        {
            Runtime.TaskQueue.Enqueue(
                TaskFactory.CreatePlugPlugs(
                    extension,
                    true,
                    TaskFactory.CreateTaskGroupId(),
                    Assembly.GetCallingAssembly(), null));
        }

        public void PlugPlugs(ExtensionInfo extension, ExtensionInfo ei)
        {
            if (ei == null)
                throw new ArgumentException();

            Runtime.TaskQueue.Enqueue(
                TaskFactory.CreatePlugPlugs(
                    extension,
                    ei,
                    true,
                    TaskFactory.CreateTaskGroupId(),
                    Assembly.GetCallingAssembly()));
        }

        public void Register(PluginInfo plugin)
        {
            Runtime.TaskQueue.Enqueue(
                TaskFactory.CreateRegister(
                    plugin,
                    true,
                    TaskFactory.CreateTaskGroupId(),
                    Assembly.GetCallingAssembly()));
        }

        public void Register(PlugTypeInfo plugTypeInfo)
        {
            Runtime.TaskQueue.Enqueue(
                TaskFactory.CreateRegister(
                    plugTypeInfo,
                    true,
                    TaskFactory.CreateTaskGroupId(),
                    Assembly.GetCallingAssembly()));
        }

        public void Register(SlotInfo slot)
        {
            Runtime.TaskQueue.Enqueue(
                TaskFactory.CreateRegister(
                    slot,
                    true,
                    TaskFactory.CreateTaskGroupId(),
                    Assembly.GetCallingAssembly()));
        }

        public void Register(PlugTypeInfo plugTypeInfo, SlotInfo si)
        {
            if (si == null)
                throw new ArgumentException();

            Runtime.TaskQueue.Enqueue(
                TaskFactory.CreateRegister(
                    plugTypeInfo,
                    si,
                    true,
                    TaskFactory.CreateTaskGroupId(),
                    Assembly.GetCallingAssembly()));
        }

        public void Register(SlotInfo slot, PlugTypeInfo pti)
        {
            if (pti == null)
                throw new ArgumentException();

            Runtime.TaskQueue.Enqueue(
                TaskFactory.CreateRegister(
                    slot,
                    pti,
                    true,
                    TaskFactory.CreateTaskGroupId(),
                    Assembly.GetCallingAssembly()));
        }

        public void RegisterInSlots(ExtensionInfo extension)
        {
            Runtime.TaskQueue.Enqueue(
                TaskFactory.CreateRegisterInSlots(
                    extension,
                    true,
                    TaskFactory.CreateTaskGroupId(),
                    Assembly.GetCallingAssembly()));
        }

        public void RegisterInSlots(ExtensionInfo extension, ExtensionTypeInfo eti)
        {
            if (eti == null)
                throw new ArgumentException();

            Runtime.TaskQueue.Enqueue(
                TaskFactory.CreateRegisterInSlots(
                    extension,
                    eti,
                    true,
                    TaskFactory.CreateTaskGroupId(),
                    Assembly.GetCallingAssembly()));
        }

        public void RegisterPlugs(ExtensionTypeInfo extensionTypeInfo)
        {
            Runtime.TaskQueue.Enqueue(
                TaskFactory.CreateRegisterPlugs(
                    extensionTypeInfo,
                    true,
                    TaskFactory.CreateTaskGroupId(),
                    Assembly.GetCallingAssembly()));
        }

        public void RegisterPlugs(ExtensionTypeInfo extensionTypeInfo, ExtensionInfo ei)
        {
            if (ei == null)
                throw new ArgumentException();

            Runtime.TaskQueue.Enqueue(
                TaskFactory.CreateRegisterInSlots(
                    ei,
                    extensionTypeInfo,
                    true,
                    TaskFactory.CreateTaskGroupId(),
                    Assembly.GetCallingAssembly()));
        }

        public void Release(ExtensionInfo extension)
        {
            Runtime.TaskQueue.Enqueue(
                TaskFactory.CreateRelease(
                    extension,
                    TaskFactory.CreateTaskGroupId(),
                    Assembly.GetCallingAssembly()));
        }

        public bool SelectPlugs(SlotInfo slot, params PlugInfo[] plugs)
        {
            return (bool)Runtime.Invoke(
                new SlotInfo.SelectPlugHandler(
                    slot.InternalSelectPlugs),
                new object[] { plugs });
        }

        public void SetAutoOpen(RuntimeBase runtime, bool value)
        {
            if (runtime.autoOpen == value)
                return;

            runtime.autoOpen = value;
            Runtime.OnPropertyChanged(this, "AutoOpen");
        }

        public void SetAutoOpen(SlotInfo slot, bool value)
        {
            if (slot.AutoOpen == value)
                return;

            slot.autoOpen = value;
            slot.OnPropertyChanged("AutoOpen");
        }

        public void SetAutoOpen(SlotTypeInfo slotTypeInfo, bool value)
        {
            if (slotTypeInfo.AutoOpen == value)
                return;

            slotTypeInfo.slotAttribute.AutoOpen = value;
            slotTypeInfo.OnPropertyChanged("AutoOpen");
        }

        public void SetAutoPlug(PlugInfo plug, bool value)
        {
            if (plug.autoPlug == value)
                return;

            plug.autoPlug = value;
            plug.OnPropertyChanged("AutoPlug");
        }

        public void SetAutoPlug(PlugTypeInfo plugTypeInfo, bool value)
        {
            if (plugTypeInfo.AutoPlug == value)
                return;

            plugTypeInfo.plugAttribute.AutoPlug = value;
            plugTypeInfo.OnPropertyChanged("AutoPlug");
        }

        public void SetAutoPlug(RuntimeBase runtime, bool value)
        {
            if (runtime.autoPlug == value)
                return;

            runtime.autoPlug = value;
            Runtime.OnPropertyChanged(this, "AutoPlug");
        }

        public void SetAutoPlug(SlotInfo slot, bool value)
        {
            if (slot.AutoPlug == value)
                return;

            slot.autoPlug = value;
            slot.OnPropertyChanged("AutoPlug");
        }

        public void SetAutoPlug(SlotTypeInfo slotTypeInfo, bool value)
        {
            if (slotTypeInfo.AutoPlug == value)
                return;

            slotTypeInfo.slotAttribute.AutoPlug = value;
            slotTypeInfo.OnPropertyChanged("AutoPlug");
        }

        public void SetAutoRegister(PlugTypeInfo plugTypeInfo, bool value)
        {
            if (plugTypeInfo.AutoRegister == value)
                return;

            plugTypeInfo.plugAttribute.AutoRegister = value;
            plugTypeInfo.OnPropertyChanged("AutoRegister");
        }

        public void SetAutoRegister(RuntimeBase runtime, bool value)
        {
            if (runtime.autoRegister == value)
                return;

            runtime.autoRegister = value;
            Runtime.OnPropertyChanged(this, "AutoRegister");
        }

        public void SetAutoRegister(SlotInfo slot, bool value)
        {
            if (slot.AutoRegister == value)
                return;

            slot.autoRegister = value;
            slot.OnPropertyChanged("AutoRegister");
        }

        public void SetAutoRegister(SlotTypeInfo slotTypeInfo, bool value)
        {
            if (slotTypeInfo.AutoRegister == value)
                return;

            slotTypeInfo.slotAttribute.AutoRegister = value;
            slotTypeInfo.OnPropertyChanged("AutoRegister");
        }

        public void SetAutoRelease(ExtensionInfo extension, bool value)
        {
            if (extension.autoRelease == value)
                return;

            extension.autoRelease = value;
            extension.OnPropertyChanged("AutoRelease");
        }

        public void SetAutoRelease(ExtensionTypeInfo extensionTypeInfo, bool value)
        {
            if (extensionTypeInfo.AutoRelease == value)
                return;

            extensionTypeInfo.extensionAttr.AutoRelease = value;
            extensionTypeInfo.OnPropertyChanged("AutoRelease");
        }

        public void SetAutoRelease(RuntimeBase runtime, bool value)
        {
            if (runtime.autoRelease == value)
                return;

            runtime.autoRelease = value;
            Runtime.OnPropertyChanged(this, "AutoRelease");
        }

        public void SetAutoRelease(SlotInfo slot, bool value)
        {
            if (slot.AutoRelease == value)
                return;

            slot.autoRelease = value;
            slot.OnPropertyChanged("AutoRelease");
        }

        public void SetAutoRelease(SlotTypeInfo slotTypeInfo, bool value)
        {
            if (slotTypeInfo.AutoRelease == value)
                return;

            slotTypeInfo.slotAttribute.AutoRelease = value;
            slotTypeInfo.OnPropertyChanged("AutoRelease");
        }

        public void SetLazyLoad(RuntimeBase runtime, bool value)
        {
            if (runtime.lazyLoad == value)
                return;

            runtime.lazyLoad = value;
            Runtime.OnPropertyChanged(this, "LazyLoad");
        }

        public void SetLazyLoad(SlotInfo slot, bool value)
        {
            if (slot.LazyLoad == value)
                return;

            slot.lazyLoad = value;
            slot.OnPropertyChanged("LazyLoad");
        }

        public void SetLazyLoad(SlotTypeInfo slotTypeInfo, bool value)
        {
            if (slotTypeInfo.LazyLoad == value)
                return;

            slotTypeInfo.slotAttribute.LazyLoad = value;
            slotTypeInfo.OnPropertyChanged("LazyLoad");
        }

        public void SetMultiple(SlotTypeInfo slotTypeInfo, bool value)
        {
            if (slotTypeInfo.Multiple == value)
                return;

            slotTypeInfo.slotAttribute.Multiple = value;
            slotTypeInfo.OnPropertyChanged("Multiple");
        }

        public bool SetSelectedPlugs(SlotInfo slot, params PlugInfo[] plugs)
        {
            return (bool)Runtime.Invoke(
                new SlotInfo.SelectPlugHandler(
                    slot.InternalSetSelectedPlugs),
                new object[] { plugs });
        }

        public void SetSelectionMode(SlotInfo slot, SelectionMode value)
        {
            if (slot.selectionMode == value)
                return;

            slot.selectionMode = value;

            if (slot.selectionMode == SelectionMode.Single && slot.selectedPlugs.Count > 1)
                slot.InternalSetSelectedPlugs(new[] { slot.selectedPlugs[0] });

            slot.OnPropertyChanged("SelectionMode");
        }

        public void SetSelectionMode(SlotTypeInfo slotTypeInfo, SelectionMode value)
        {
            if (slotTypeInfo.SelectionMode == value)
                return;

            slotTypeInfo.slotAttribute.SelectionMode = value;
            slotTypeInfo.OnPropertyChanged("SelectionMode");
        }

        public void SetUnique(SlotInfo slot, bool value)
        {
            if (slot.Unique == value)
                return;

            slot.unique = value;
            slot.OnPropertyChanged("Unique");
        }

        public void SetUnique(SlotTypeInfo slotTypeInfo, bool value)
        {
            if (slotTypeInfo.Unique == value)
                return;

            slotTypeInfo.slotAttribute.Unique = value;
            slotTypeInfo.OnPropertyChanged("Unique");
        }

        public void Unplug(PlugInfo plug)
        {
            Runtime.TaskQueue.Enqueue(
                TaskFactory.CreateUnplug(
                    plug,
                    TaskFactory.CreateTaskGroupId(),
                    Assembly.GetCallingAssembly()));
        }

        public void Unplug(SlotInfo slot)
        {
            Runtime.TaskQueue.Enqueue(
                TaskFactory.CreateUnplug(
                    slot,
                    TaskFactory.CreateTaskGroupId(),
                    Assembly.GetCallingAssembly()));
        }

        public void Unplug(PlugInfo plug, SlotInfo si)
        {
            if (si == null)
                throw new ArgumentException();

            Runtime.TaskQueue.Enqueue(
                TaskFactory.CreateUnplug(
                    plug,
                    si,
                    TaskFactory.CreateTaskGroupId(),
                    Assembly.GetCallingAssembly()));
        }

        public void Unplug(SlotInfo slot, PlugInfo pi)
        {
            if (pi == null)
                throw new ArgumentException();

            Runtime.TaskQueue.Enqueue(
                TaskFactory.CreateUnplug(
                    slot,
                    pi,
                    TaskFactory.CreateTaskGroupId(),
                    Assembly.GetCallingAssembly()));
        }

        public void UnplugFromSlots(ExtensionInfo extension)
        {
            Runtime.TaskQueue.Enqueue(
                TaskFactory.CreateUnplugFromSlots(
                    extension,
                    TaskFactory.CreateTaskGroupId(),
                    Assembly.GetCallingAssembly()));
        }

        public void UnplugFromSlots(ExtensionInfo extension, ExtensionInfo ei)
        {
            if (ei == null)
                throw new ArgumentException();

            Runtime.TaskQueue.Enqueue(
                TaskFactory.CreateUnplugFromSlots(
                    extension,
                    ei,
                    TaskFactory.CreateTaskGroupId(),
                    Assembly.GetCallingAssembly()));
        }

        public void UnplugPlugs(ExtensionInfo extension)
        {
            Runtime.TaskQueue.Enqueue(
                TaskFactory.CreateUnplugPlugs(
                    extension,
                    TaskFactory.CreateTaskGroupId(),
                    Assembly.GetCallingAssembly()));
        }

        public void UnplugPlugs(ExtensionInfo extension, ExtensionInfo ei)
        {
            if (ei == null)
                throw new ArgumentException();

            Runtime.TaskQueue.Enqueue(
                TaskFactory.CreateUnplugPlugs(
                    extension,
                    TaskFactory.CreateTaskGroupId(),
                    Assembly.GetCallingAssembly()));
        }
    }
}

